﻿using Kinlo.Entitys;
using Kinlo.MESDocking;
using MaterialDesignThemes.Wpf;
using Microsoft.Xaml.Behaviors.Layout;
using Newtonsoft.Json.Linq;
using NPOI.OpenXmlFormats.Vml;
using NPOI.SS.Formula.Functions;
using Org.BouncyCastle.Asn1.BC;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing.Text;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Input;
using UIWindows.Attributes;
using UIWindows.Domains;
using UIWindows.Enums;
using UIWindows.GlobalStatics;
using UIWindows.Models;
using UIWindows.Models.Devices;
using UIWindows.Models.Homes;
using UIWindows.Models.MES;
using UIWindows.Services.Handle;
using UIWindows.Tools.Helper;
using XingLucifer.Devices;
using XingLucifer.IBase;
using XingLucifer.IBase.Enums;
using static log4net.Appender.RollingFileAppender;

namespace UIWindows.Services
{
    public class TaskService
    {
        private CancellationTokenSource _taskToken;
        private Dictionary<string, object> _tasks = default;
        private ConcurrentDictionary<string, object> _taskcd = default;
        #region 单例模式
        private static readonly object _lock = new object();
        private static TaskService taskService = default;

        public static TaskService Instance
        {
            get {
                if (taskService == null)
                {
                    lock (_lock)
                    {
                        if (taskService == null)
                        {
                            taskService = new TaskService();
                        }
                    }
                }
                return taskService;
            }
        }
        #endregion
        private SystemConfigStatic _systemConfigStatic;
        private DeviceConfigStatic _deviceConfig;
        private TemporaryStatic _temporaryStatic;
        private ParameterStatic _parameterStatic;
        private TaskService()
        {
            _taskToken = new CancellationTokenSource();
            _tasks = new Dictionary<string, object>();
            _taskcd = new ConcurrentDictionary<string, object>();
            _systemConfigStatic = ObjectContainer.ResolveSingleton<SystemConfigStatic>();
            _deviceConfig = ObjectContainer.ResolveSingleton<DeviceConfigStatic>();
            _temporaryStatic = ObjectContainer.ResolveSingleton<TemporaryStatic>();
            _parameterStatic = ObjectContainer.ResolveSingleton<ParameterStatic>();
            //HeartBeatThread();
            //ProcessDataUpload();//实时数据上传
        }

        private void InitTask()
        {
            _temporaryStatic.DeviceStatus.Clear();
            _tasks.Clear();
            foreach (var signal in _systemConfigStatic.SignalList)
            {
                _temporaryStatic.DeviceStatus.Add(signal.Name, 0);
                var iAddressList = _systemConfigStatic.IAddressList.Where(x => x.ServiceName == signal.Name);
                foreach (var item in iAddressList)
                {
                    var handlerType = typeof(Context.DataContext);
                    object? obj = Activator.CreateInstance(handlerType);
                    var objProper = handlerType.GetProperties();
                    objProper.Where(x => x.Name == "TaskType").FirstOrDefault()?.SetValue(obj, item.TaskType);
                    objProper.Where(x => x.Name == "DeviceType").FirstOrDefault()?.SetValue(obj, item.DeviceType);
                    objProper.Where(x => x.Name == "AddressingMethod").FirstOrDefault()?.SetValue(obj, signal.AddressingMethod);
                    objProper.Where(x => x.Name == "Address_Signal").FirstOrDefault()?.SetValue(obj, (ushort)((item.Index - 1) * (signal.AddressingMethod == "字节" ? 2 : 1) + signal.Address_Start));
                    objProper.Where(x => x.Name == "Address_Struct").FirstOrDefault()?.SetValue(obj, item.Address_Struct);
                    objProper.Where(x => x.Name == "Struct_Length").FirstOrDefault()?.SetValue(obj, item.Struct_Length);
                    objProper.Where(x => x.Name == "DeviceIndex").FirstOrDefault()?.SetValue(obj, item.DeviceIndex);
                    objProper.Where(x => x.Name == "ServiceName").FirstOrDefault()?.SetValue(obj, item.ServiceName);
                    _tasks.Add($"{signal.Name}{item.TaskType.GetHashCode()}{item.DeviceType.GetHashCode()}{item.Address_Struct}{item.DeviceIndex}", obj);
                }
            }
        }

        public async Task<bool> SwitchOn()
        {
            if (_taskToken.Token.IsCancellationRequested) { _taskToken = new CancellationTokenSource(); }
            if (await DeviceLink()) 
            {
                try
                {
                    _temporaryStatic.IsRunStatus = true;
                    _temporaryStatic.ExcisionList.Clear();
                    _temporaryStatic.IsExcision = System.Windows.Visibility.Collapsed;
                    InitTask();
                    foreach (var item in _systemConfigStatic.SignalList)
                    {
                        if (item.DeviceType == DeviceTypes.NONE)
                        {
                            continue;
                        }
                        var serviceList = _temporaryStatic.LinkList.FirstOrDefault(x => x.ServiceName == "上位机状态");
                        if (serviceList != null) { serviceList.Status = true; }
                        $"扫描线程 [{item.Name}] 启动".RunLog(MessageLevelType.信息);
                        ThreadPool.QueueUserWorkItem(new WaitCallback(ScanSignal => 
                        {
                            try
                            {
                                int count_Heartbeat = 0;
                                Models.Interact.ScanSignalModel ssModel = (Models.Interact.ScanSignalModel)ScanSignal;
                                bool[] bools = new bool[ssModel.Length_Resection];
                                var taskList = new Dictionary<string, object>();
                                foreach (var item in _tasks.Where(x => x.Key.Contains(ssModel.Name)))
                                {
                                    taskList.Add(item.Key, item.Value);
                                }
#pragma warning disable CS8600 // 将 null 字面量或可能为 null 的值转换为非 null 类型。
                                var plc = _deviceConfig.DeviceList.FirstOrDefault(t => t.DeviceType == ssModel.DeviceType && t.ServiceName == ssModel.Name);
#pragma warning restore CS8600 // 将 null 字面量或可能为 null 的值转换为非 null 类型。
                                if (plc == null) { return; }
                                //plc.Communication.WriteSingle((ushort)(_parameterStatic.DecideParameter.EnableMES ? 1 : 2), 2228, 0, 0);
                                Models.Interact.PLCSignalModel signalData = new Models.Interact.PLCSignalModel(ssModel.Length_Signal, ssModel.Length_Resection);
                                StringBuilder key = new StringBuilder();
                                int count = 0;
                                while (!_taskToken.Token.IsCancellationRequested)
                                {
                                    try
                                    {
                                        if (plc.Communication.ReadClass(ssModel.Address_Start, signalData) != null)
                                        {
                                            for (int i = 0; i < ssModel.Length_Signal; i++)
                                            {
                                                if (signalData.Cmd[i] == 1 || (signalData.Cmd[i] != _temporaryStatic.DeviceStatus[ssModel.Name] && i == 0))
                                                {
                                                    key.Clear();
                                                    var model = _systemConfigStatic.IAddressList.FirstOrDefault(x => x.Index == (i + 1) && x.ServiceName == ssModel.Name);
                                                    if (model != null)
                                                    {
                                                        if (model.TaskType == TaskTypes.设备状态)
                                                        {
                                                            if (_temporaryStatic.DeviceStatus[ssModel.Name] == signalData.Cmd[i])
                                                            {
                                                                continue;
                                                            }
                                                            _temporaryStatic.DeviceStatus[ssModel.Name] = signalData.Cmd[i];
                                                        }
                                                        try
                                                        {
                                                            key.Append($"{model.ServiceName}{model.TaskType.GetHashCode()}{model.DeviceType.GetHashCode()}{model.Address_Struct}{model.DeviceIndex}");
                                                            if (_taskcd.ContainsKey(key.ToString()) || !_taskcd.TryAdd(key.ToString(), default)) { continue; }
                                                            TaskEventModel obj = ObjectContainer.ResolveEvent(model.TaskType);
                                                            ThreadPool.QueueUserWorkItem(new WaitCallback(sender => obj?.Handle.Invoke(obj.TaskObject, new object[] { sender })),
                                                                taskList[key.ToString()]);
                                                        }
                                                        catch (Exception ex)
                                                        {
                                                            $"[{ssModel.Name}] [{model.TaskType}]信号触发异常：{ex}".RunLog(MessageLevelType.错误);
                                                        }
                                                    }
                                                }
                                            }
                                            for (int i = 0; i < ssModel.Length_Resection; i++)
                                            {
                                                if (signalData.Resection[i] && !bools[i])
                                                {
                                                    var resection = _systemConfigStatic.PLCResectionList.FirstOrDefault(x => x.ServiceName == ssModel.Name && x.Index == (i + 1));
                                                    if (resection != null)
                                                    {
                                                        resection.IsExcision = true;
                                                        $"[{ssModel.Name}] 注意：[{resection.Name}] 切除功能已启用！！！".RunLog(MessageLevelType.警告);
                                                        ThreadHelper.CrossThread(x => _temporaryStatic.ExcisionList.Add(resection), 0);
                                                    }
                                                }
                                                else if (!signalData.Resection[i] && bools[i])
                                                {
                                                    var resection = _systemConfigStatic.PLCResectionList.FirstOrDefault(x => x.ServiceName == ssModel.Name && x.Index == (i + 1));
                                                    if (resection != null)
                                                    {
                                                        resection.IsExcision = false;
                                                        $"[{ssModel.Name}] 注意：[{resection.Name}] 切除功能已关闭！！！".RunLog(MessageLevelType.成功);
                                                        ThreadHelper.CrossThread(x => _temporaryStatic.ExcisionList.Remove(resection), 0);
                                                    }
                                                }
                                                bools[i] = signalData.Resection[i];
                                            }
                                        }
                                        else
                                        {
                                            count += 1;
                                            if (count == 2)
                                            {
                                                $"[{ssModel.Name}] 连续扫描线程异常，退出任务！！！".RunLog(MessageLevelType.错误);
                                                _taskToken.Cancel();
                                                break;
                                            }
                                            Thread.Sleep(500);
                                            continue;
                                        }
                                        count_Heartbeat++;
                                        if (count_Heartbeat >= 20)
                                        {
                                            plc.Communication.WriteSingle((ushort)1, ssModel.Heartbeat, 0, 0);
                                            count_Heartbeat = 0;
                                        }
                                        count = 0;
                                        _temporaryStatic.IsExcision = _temporaryStatic.ExcisionList.Count > 0 ? System.Windows.Visibility.Visible : System.Windows.Visibility.Collapsed;
                                    }
                                    catch (Exception ex)
                                    {
                                        if (count == 2)
                                        {
                                            $"[{ssModel.Name}] 连续扫描信号异常，退出任务！！！".RunLog(MessageLevelType.错误);
                                            _taskToken.Cancel();
                                            break;
                                        }
                                        $"信号扫描线程异常：{ex}".RunLog(MessageLevelType.错误);
                                        count++;
                                        Thread.Sleep(500);
                                    }
                                    Thread.Sleep(20);
                                }
                                count = 0;
                                while (_taskcd.Count != 0)
                                {
                                    Thread.Sleep(500);
                                    if (count > 60)
                                    {
                                        _taskcd.Clear();
                                    }
                                    $"第 [{++count}] 次 等待所有任务退出.....".RunLog(MessageLevelType.警告);
                                }
                            }
                            catch (Exception ex)
                            {
                                $"扫描线程执行异常：{ex}".RunLog(MessageLevelType.错误);
                            }
                            //退出扫描线程后的任务
                            _taskcd.Clear();
                            _temporaryStatic.IsRunStatus = false;
                            CloseDevice();
                            ThreadHelper.CrossThread(x =>
                            {
                                if (_systemConfigStatic.SCM.PerformTaskName.Content.ToString() != "    运  行    ")
                                {
                                    _systemConfigStatic.SCM.PerformTaskName.Content = "    运  行    ";
                                }
                                if (DialogHost.IsDialogOpen(PopUpTypes.Global.ToString())) DialogHost.Close(PopUpTypes.Global.ToString());
                            }, 0);
                            var serviceList = _temporaryStatic.LinkList.FirstOrDefault(x => x.ServiceName == "上位机状态");
                            if (serviceList != null) { serviceList.Status = false; }
                        }), item);
                    }
                    return true;
                }
                catch (Exception ex)
                {
                    $"启动任务异常：{ex}".RunLog(MessageLevelType.错误);
                    _temporaryStatic.IsRunStatus = false;
                    return false;
                }
            }
            _ = "设备链接失败!!!\r\n请前往设备管理查看\r\n黄色：设备通信异常\r\n绿色：设备正常通信".MessageDialogs(MessageLevelType.错误, true, Enums.PopUpTypes.Global);
            _taskToken.Cancel();
            CloseDevice();
            return false;
        }

    

     

        private void CloseDevice()
        {
            foreach (var item in _deviceConfig.DeviceList)
            {
                if (item.Communication == null)
                {
                    continue;
                }
                try
                {
                    item.Communication.Close();
                    item.Communication = null;
                }
                catch (Exception ex)
                {
                    $"释放异常：{ex}".RunLog(MessageLevelType.信息);
                }
            }
        }

        public bool RemoveTask(Context.DataContext model) => _taskcd.TryRemove($"{model.ServiceName}{model.TaskType.GetHashCode()}{model.DeviceType.GetHashCode()}{model.Address_Struct}{model.DeviceIndex}", out _);
        public void SwitchOFF() => _taskToken.Cancel();

        public async Task<bool> DeviceLink()
        {
            return await Task.Run(() => Parallel.ForEach(_deviceConfig.DeviceList, (x, _parallelLoopState) =>
            {

                if (x.Index == 0 || string.IsNullOrEmpty(x.IPCOM) || x.Index == 999) { return; }
                ICommunication com = null;
                EndianTypes endianTypes = EndianTypes.Fins;
                switch (x.DeviceType)
                {
                    case DeviceTypes.NJ_FINS_PLC:
                        endianTypes = EndianTypes.Fins;
                        break;
                    case DeviceTypes.Modbus_TCP_ABCD:
                        endianTypes = EndianTypes.Modbus_ABCD;
                        break;
                    case DeviceTypes.Modbus_TCP_BADC:
                        endianTypes = EndianTypes.Modbus_BADC;
                        break;
                    case DeviceTypes.Modbus_TCP_DCBA:
                        endianTypes = EndianTypes.Modbus_DCBA;
                        break;
                    case DeviceTypes.Modbus_TCP_CDAB:
                        endianTypes = EndianTypes.Modbus_CDAB;
                        break;
                    case DeviceTypes.DTSU666:
                        endianTypes = EndianTypes.Modbus_ABCD;
                        break;
                }
                if (x.IsSocket)
                {
                    com = new TCPCom(_systemConfigStatic.SCM.FinsIP, x.IPCOM, x.Port, x.DeviceType, x.Index, x.TaskType, x.ServiceName, _taskToken, endianTypes);
                }
                else
                {
                    com = new SerialPortCom(_systemConfigStatic.SCM.FinsIP, x.IPCOM, x.Port, 
                        System.IO.Ports.Parity.None, 8, System.IO.Ports.StopBits.One, x.DeviceType, x.Index, x.TaskType, x.ServiceName, _taskToken, endianTypes);
                }
                com.ReconnectDisconnection += Device_DropAlarms;
               
               IDevices model = EquipmentFactory.NewSocketDevice(_systemConfigStatic.SCM.FinsIP, x.IPCOM, x.Port, x.DeviceType, x.Index, x.TaskType, x.ServiceName, _taskToken, com);
                
                    if (model == null)
                    {
                        return;
                    }
                //bool bools=false;
                //try
                //{
                //     bools = model.Open();
                //}
                //catch (Exception ex)
                //{
                //    Console.WriteLine(ex.ToString());
                //}
                bool? bools = model.Open();

                if (bools != null && bools == true)
                {
                    if (x.DeviceType == DeviceTypes.AND4531B_Scale
                    || x.DeviceType == DeviceTypes.TC06_Scale || x.DeviceType == DeviceTypes.RD900M)
                    {
                        _ = model.Read();
                    }
                    x.Communication = model;
                }
                else
                {
                    _parallelLoopState.Stop();
                    $"设备：[{x.TaskType}] 序号：[{x.Index}] IP：[{x.IPCOM}] 端口号：[{x.Port}] 连接失败".RunLog(MessageLevelType.错误);
                }


            }).IsCompleted);


        }

        private bool Device_DropAlarms(ICommunication com, int index, string ipcom, int port, DeviceTypes deviceTypes, TaskTypes taskType, string serviceName, CancellationTokenSource token)
        {
            try
            {
                DeviceClientModel device = _deviceConfig.DeviceList.FirstOrDefault(t => t.DeviceType == deviceTypes && t.IPCOM == ipcom && t.Index == index && t.Port == port && t.TaskType == taskType && t.ServiceName == serviceName);
                if (token.Token.IsCancellationRequested || device.Communication == null)
                {
                    return false;
                }
                device.Communication.Close();
                Thread.Sleep(500);
                if (device.Communication.Open())
                {
                    $"工位：[{taskType}] 设备：[{deviceTypes}] 序号：[{index}] IP：[{ipcom}] 端口号：[{port}]---重连成功！".RunLog(MessageLevelType.成功);
                    return true;
                }
                Thread.Sleep(500);
                $"工位：[{taskType}] 设备：[{deviceTypes}] 序号：[{index}] IP：[{ipcom}] 端口号：[{port}]---重连失败...".RunLog(MessageLevelType.错误);
            }
            catch (Exception ex)
            {
                Thread.Sleep(500);
                $"工位：[{taskType}] 设备重连异常：{ex}".RunLog(MessageLevelType.错误);
            }
            return false;
        }

        /// <summary>
        /// 点检功能
        /// </summary>
        /// <returns></returns>
        public void SpotCheck()
        {
            Task.Run(() =>
            {
                DateTime dateTime = DateTime.Now;
                double now = dateTime.TimeOfDay.TotalMilliseconds;
                double stat = new DateTime(dateTime.Year, dateTime.Month, dateTime.Day, 7, 30, 0).TimeOfDay.TotalMilliseconds;
                double end = new DateTime(dateTime.Year, dateTime.Month, dateTime.Day, 8, 30, 0).TimeOfDay.TotalMilliseconds;
                bool flas = (now - stat) < 0 && (now - end) > 0;
                FunctionSpotCheckModel spotCheck = new FunctionSpotCheckModel();
                var plc = _deviceConfig.DeviceList.FirstOrDefault(t => t.TaskType == TaskTypes.扫描信号);
                while (!_taskToken.Token.IsCancellationRequested)
                {
                    dateTime = DateTime.Now;
                    now = dateTime.TimeOfDay.TotalMilliseconds;
                    stat = new DateTime(dateTime.Year, dateTime.Month, dateTime.Day, 7, 30, 0).TimeOfDay.TotalMilliseconds;
                    end = new DateTime(dateTime.Year, dateTime.Month, dateTime.Day, 8, 30, 0).TimeOfDay.TotalMilliseconds;
                    if ((now - stat) >= 0 && (now - end) <= 0)
                    {
                        if (!flas)
                        {
                            flas = true;
                            try
                            {
                                FunctionSpotCheckModel function = plc.Communication.ReadClass<FunctionSpotCheckModel>(30100);
                                if (function != null)
                                {
                                    PLC_FunctionSpotCheckModel plc_Function = new PLC_FunctionSpotCheckModel();
                                    var objProper = spotCheck.GetType().GetProperties();
                                    var plc_Proper = plc_Function.GetType().GetProperties();
                                    foreach (var item in function.GetType().GetProperties())
                                    {
                                        PropertyInfo op = objProper.Where(x => x.Name == item.Name).FirstOrDefault();
                                        if ((item.GetValue(function) as ushort?) != (op.GetValue(spotCheck) as ushort?))
                                        {
                                            PropertyInfo property = plc_Proper.Where(x => x.Name == item.Name).FirstOrDefault();
                                            property.SetValue(plc_Function, true);
                                        }
                                    }
                                    plc.Communication.WriteClass(plc_Function, 30000);
                                }
                            }
                            catch (Exception ex)
                            {

                            }
                        }
                    }
                    else
                    {
                        flas = false;
                    }
                    Thread.Sleep(1000);
                }
            });
        }
    }
}
